package service

import (
	"MyBlogv2/common/Enum"
	"MyBlogv2/common/HttpCode"
	"MyBlogv2/common/define"
	helper2 "MyBlogv2/common/helper"
	"MyBlogv2/common/models"
	"MyBlogv2/common/oss"
	"MyBlogv2/common/response"
	"context"
	"fmt"
	"path"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/jinzhu/copier"
)

func Register(c *gin.Context) {
	var user models.UserRegisterDto
	if err := c.ShouldBindJSON(&user); err != nil {
		response.ResponseError(c, HttpCode.PARAM_ERROR)
	}
	
	// 检查用户名是否已存在
	var usernameCount int64
	models.Db.Model(new(models.User)).Where("username = ?", user.Username).Count(&usernameCount)
	if usernameCount > 0 {
		response.ResponseError(c, HttpCode.USERNAME_OR_EMAIL_EXIST)
		return
	}
	
	// 检查邮箱是否已存在
	var emailCount int64
	models.Db.Model(new(models.User)).Where("email = ?", user.Email).Count(&emailCount)
	if emailCount > 0 {
		response.ResponseError(c, HttpCode.USERNAME_OR_EMAIL_EXIST)
		return
	}
	
	code, err := models.RDb.Get(context.Background(), user.Email).Result()
	if err != nil {
		fmt.Println("验证码过期")
		response.ResponseError(c, HttpCode.VERIFY_CODE_ERROR)
		return
	}
	if user.Code != code {
		fmt.Println("验证码错误")
		response.ResponseError(c, HttpCode.VERIFY_CODE_ERROR)
		return
	}
	user.Password, _ = helper2.GetBcryptPassword(user.Password)
	var userRegister models.User
	copier.Copy(&userRegister, &user)
	userRegister.RegisterIp = c.ClientIP()
	userRegister.RegisterType = Enum.GetType(Enum.EMAIL)
	userRegister.Gender = define.DEFAULT_GENDER
	userRegister.Avatar = define.DEFAULT_AVATAR
	userRegister.Intro = define.DEFAULT_INTRODUCTION
	userRegister.Nickname = user.Username
	userRegister.LoginTime = models.MyTime(time.Now())
	userRegister.IsDisAble = define.DEFAULT_STATUS
	userRegister.IsDeleted = define.DEFAULT_STATUS
	models.RDb.Del(context.Background(), user.Email)
	err = models.Db.Create(&userRegister).Error
	if err != nil {
		response.ResponseError(c, HttpCode.FAILURE)
		return
	}
	response.ResponseOK(c, nil)
}

func Login(c *gin.Context) {
	username := c.PostForm("username")
	password := c.PostForm("password")
	fmt.Println(username)
	fmt.Println(password)
	var user models.User
	err := models.Db.Model(new(models.User)).Where("username = ?", username).First(&user).Error
	if err != nil {
		response.ResponseError(c, HttpCode.USERNAME_OR_PASSWORD_ERROR)
		return
	}
	if !helper2.AnalysisBcryptPassword(user.Password, password) {
		response.ResponseError(c, HttpCode.USERNAME_OR_PASSWORD_ERROR)
		return
	}

	models.Db.Model(new(models.User)).Where("id = ?", user.Id).Update("login_time", models.MyTime(time.Now()))
	token, err := helper2.GenerateToken(user.Id)
	if err != nil {
		response.ResponseError(c, HttpCode.FAILURE)
		return
	}
	// 返回 token 具体到期时间（毫秒级时间戳，与 GenerateToken 中 ExpiresAt 保持一致，这里为当前时间 + 30 天）
	response.ResponseOK(c, gin.H{
		"token":  token,
		"expire": time.Now().Add(time.Hour * 24 * 30).UnixMilli(),
	})
}

func GetUserInfo(c *gin.Context) {
	var user models.UserVo
	var userAccountVo models.UserAccountVo
	userId, _ := c.Get("userId")
	models.Db.Model(new(models.UserVo)).Where("id = ?", userId).First(&user)
	copier.Copy(&userAccountVo, &user)
	
	// 查询用户角色
	var roles []string
	models.Db.Model(new(models.UserRole)).
		Table("sys_user_role ur").
		Select("r.role_key").
		Joins("left join sys_role r on ur.role_id = r.id").
		Where("ur.user_id = ?", userId).
		Find(&roles)
	userAccountVo.Roles = roles
	
	// 查询用户权限
	// var permissions []string
	// models.Db.Model(new(models.UserRole)).
	// 	Table("sys_user_role ur").
	// 	Select("p.permission_key").
	// 	Joins("left join sys_role_permission rp on ur.role_id = rp.role_id").
	// 	Joins("left join sys_permission p on rp.permission_id = p.id").
	// 	Where("ur.user_id = ?", userId).
	// 	Find(&permissions)
	// userAccountVo.Permissions = permissions
	
	response.ResponseOK(c, userAccountVo)
}

func UpdateAvatar(c *gin.Context) {
	userId, _ := c.Get("userId")
	file, _ := c.FormFile("avatarFile")
	filename := file.Filename
	ext := path.Ext(filename)
	objectName := helper2.GetUUID() + ext
	filePath, err := file.Open()
	if err != nil {
		response.ResponseError(c, HttpCode.FILE_UPLOAD_ERROR)
		return
	}
	uploadFilePath, err := oss.UploadFile(objectName, filePath)
	if err != nil {
		response.ResponseError(c, HttpCode.FILE_UPLOAD_ERROR)
		return
	}
	models.Db.Model(new(models.User)).Where("id = ?", userId).Update("avatar", uploadFilePath)
	response.ResponseOK(c, uploadFilePath)
}

func UpdateUserInfo(c *gin.Context) {
	userId, _ := c.Get("userId")
	var userUpdateDto models.UserUpdateDto
	if err := c.ShouldBindJSON(&userUpdateDto); err != nil {
		response.ResponseError(c, HttpCode.PARAM_ERROR)
		return
	}
	models.Db.Model(new(models.User)).Where("id = ?", userId).Updates(userUpdateDto)
	response.ResponseOK(c, nil)
}

func Logout(c *gin.Context) {
	response.ResponseOK(c, nil)
}
func GetUserList(c *gin.Context) {
	pageNum, _ := strconv.Atoi(c.DefaultQuery("pageNum", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	var userList []models.UserListVo
	var total int64
	models.Db.Model(new(models.UserListVo)).
		Count(&total).
		Order("created_at desc").
		Offset((pageNum - 1) * pageSize).
		Limit(pageSize).
		Find(&userList)
	response.ResponseOK(c, gin.H{
		"page":  userList,
		"total": total,
	})
}
func SearchUserList(c *gin.Context) {
	var userList []models.UserListVo
	var userSearchDto models.UserSearchDto
	if err := c.ShouldBindJSON(&userSearchDto); err != nil {
		response.ResponseError(c, HttpCode.PARAM_ERROR)
	}
	db := models.Db.Model(new(models.UserListVo))
	if userSearchDto.Username != "" {
		db.Where("username like ?", "%"+userSearchDto.Username+"%")
	}
	if userSearchDto.Email != "" {
		db.Where("email like ?", "%"+userSearchDto.Email+"%")
	}
	if userSearchDto.IsDisable.Valid {
		db.Where("is_disable = ?", userSearchDto.IsDisable.Int64)
	}
	if !time.Time(userSearchDto.CreateTimeStart).IsZero() {
		db.Where("created_at >= ?", userSearchDto.CreateTimeStart)
	}
	if !time.Time(userSearchDto.CreateTimeEnd).IsZero() {
		db.Where("created_at <= ?", userSearchDto.CreateTimeEnd)
	}
	db.Find(&userList)
	response.ResponseOK(c, userList)
}

func FindUserDetailById(c *gin.Context) {
	id, _ := strconv.Atoi(c.Param("id"))
	var user models.UserDetailsVo
	models.Db.Model(new(models.UserDetailsVo)).Where("id = ?", id).Find(&user)
	var roles []string
	models.Db.Model(new(models.UserRole)).
		Table("sys_user_role ur").
		Select("r.role_key").
		Joins("left join sys_role r on ur.role_id = r.id").
		Where("ur.user_id = ?", id).Find(&roles)
	user.Roles = roles
	response.ResponseOK(c, user)
}

func UpdateUserStatus(c *gin.Context) {
	var updateUserStatusDto models.UpdateUserStatusDto
	if err := c.ShouldBindJSON(&updateUserStatusDto); err != nil {
		response.ResponseError(c, HttpCode.PARAM_ERROR)
		return
	}
	models.Db.Model(new(models.User)).Where("id = ?", updateUserStatusDto.Id).Update("is_disable", updateUserStatusDto.Status)
	response.ResponseOK(c, nil)
}

func DeleteUserByIds(c *gin.Context) {
	var userDeleteDto models.UserDeleteDto
	if err := c.ShouldBindJSON(&userDeleteDto); err != nil {
		response.ResponseError(c, HttpCode.PARAM_ERROR)
		return
	}
	models.Db.Model(new(models.User)).Where("id in (?)", userDeleteDto.Ids).Delete(new(models.User))
	models.Db.Model(new(models.UserRole)).Where("user_id in (?)", userDeleteDto.Ids).Delete(new(models.UserRole))
	models.Db.Model(new(models.Comment)).Where("user_id in (?)", userDeleteDto.Ids).Delete(new(models.Comment))
	models.Db.Model(new(models.Like)).Where("user_id in (?)", userDeleteDto.Ids).Delete(new(models.Like))
	models.Db.Model(new(models.Favorite)).Where("user_id in (?)", userDeleteDto.Ids).Delete(new(models.Favorite))
	models.Db.Model(new(models.Article)).Where("user_id in (?)", userDeleteDto.Ids).Delete(new(models.Article))
	models.Db.Model(new(models.LeaveWord)).Where("user_id in (?)", userDeleteDto.Ids).Delete(new(models.LeaveWord))
	models.Db.Model(new(models.TreeHole)).Where("user_id in (?)", userDeleteDto.Ids).Delete(new(models.TreeHole))
	//TODO友链
	response.ResponseOK(c, nil)
}
